package top.as.sean.api.aspect;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import top.as.sean.common.gson.GsonUtil;
import top.as.sean.common.ip2region.Ip2regionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 接口操作日志
 *
 * @author: ArchieSean
 * @create: 2022/11/18
 */
@Aspect
@Slf4j
@Component
@AllArgsConstructor
public class LogAspect {
    private final HttpServletRequest request;

    /**
     * 经过代理后存储ip的位置
     */
    private final static String HEAD_IP = "X-Forwarded-For";
    /**
     * 多级代理后，真实ip位置
     */
    private final static String REAL_IP = "X-REAL-IP";

    /**
     * ip归属地查询
     */
    private final Ip2regionUtils ip2regionUtils;

    /**
     * 切入点表达式
     */
    @Pointcut("execution(* top.as.sean.api.controller.*..*.*(..))")
    private void pointCut() {
    }

    /**
     * 环绕通知
     *
     * @param pjp 连接点
     * @return obj
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();
        //获取请求参数
        Map<String, String[]> params = request.getParameterMap();
        //获取请求方法路径
        String uri = request.getRequestURI();
        //获取请求方式
        String method = request.getMethod();
        //获取请求ip
        String ip = getRemoteIp();
        //执行方法
        Object obj = pjp.proceed();
        //ip归属地
        String ipHome = ip2regionUtils.getIpHome(ip);
        long longTime = System.currentTimeMillis() - startTime;
        log.info("请求IP：【{}】,ip归属地：【{}】,URI：【{}】,method：【{}】,api耗时【{}】毫秒,params：【{}】,response：【{}】",
                ip, ipHome, uri, method, longTime, GsonUtil.toGsonString(params), GsonUtil.toGsonString(obj));
        return obj;
    }

    /**
     * 用于获取客户端真实ip
     *
     * @return ip
     */
    private String getRemoteIp() {
        String ipAll = request.getHeader(HEAD_IP);
        String ip = null;
        log.info("获取用户IPAll_{}", ipAll);
        if (!ObjectUtils.isEmpty(ipAll)) {
            ip = ipAll;
            log.info("获取用户IP_1_{}", ip);
        }
        if (ip == null || ip.length() == 0) {
            ip = request.getHeader(REAL_IP);
            log.info("获取用户IP_2_{}", ip);
        }
        if (ip == null || ip.length() == 0) {
            ip = request.getRemoteAddr();
            log.info("获取用户IP_3_{}", ip);
        }
        return ip;
    }
}
